课程
1
Spring Cloud Alibaba 项目实战:点亮微服务技能点!
学习时长: 10分6秒
2
项目须知和课程约定
学习时长: 7分37秒
3
漫谈微服务架构(一)
学习时长: 16分27秒
4
漫谈微服务架构(二)
学习时长: 6分56秒
5
漫谈微服务架构(三)
学习时长: 6分13秒
6
微服务落地一站式解决方案——Spring Cloud
学习时长: 13分50秒
7
实战基础1-代码运行环境及开发工具介绍
学习时长: 20分5秒
8
实战基础2-Spring Boot 开发介绍及Spring Cloud Alibaba模板项目构建
学习时长: 42分46秒
9
服务通信基础讲解
学习时长: 27分11秒
10
微服务架构中的服务治理
学习时长: 7分56秒
11
Nacos安装与配置
学习时长: 20分31秒
12
Nacos整合之服务注册编码实践
学习时长: 46分48秒
13
Nacos整合之服务发现编码实践
学习时长: 59分28秒
14
[补充章节]谈一谈配置中心
学习时长: 13分8秒
15
[补充章节]整合Nacos配置中心编码实践
学习时长: 30分47秒
16
[补充章节]配置动态刷新及多配置读取编码实践
学习时长: 17分57秒
17
服务通信之负载均衡器
学习时长: 12分45秒
18
负载均衡器的源码分析及自定义负载均衡算法
学习时长: 46分24秒
19
服务治理与服务通信总结
学习时长: 18分35秒
20
OpenFeign介绍与整合
学习时长: 18分45秒
21
OpenFeign参数传递编码实践
学习时长: 51分14秒
22
服务网关之Spring Cloud Gateway
学习时长: 9分19秒
23
整合Spring Cloud Gateway编码实践
学习时长: 19分37秒
24
服务网关Spring Cloud Gateway之Predicate(断言)
学习时长: 22分38秒
25
服务网关Spring Cloud Gateway之Filter(过滤器)
学习时长: 33分20秒
26
微服务最终实战项目的启动和运行注意事项
学习时长: 23分22秒
27
最终实战项目的功能介绍与功能演示
学习时长: 43分26秒
28
分布式事务问题演示
学习时长: 1小时46分
29
分布式事务解决方案及Seata搭建
学习时长: 23分56秒
30
整合Seata编码实践
学习时长: 18分35秒
31
Seata的运行流程分析
学习时长: 27分12秒
32
服务容错之限流与熔断
学习时长: 15分41秒
33
服务容错之Sentinel限流配置实践
学习时长: 23分49秒
34
服务容错之Sentinel降级熔断配置实践
学习时长: 12分40秒
35
链路追踪之Sleuth+Zipkin整合
学习时长: 51分47秒
36
从零到一搭建微服务项目编码实战(一)
学习时长: 1小时9分
37
从零到一搭建微服务项目编码实战(二)
学习时长: 40分19秒
38
从零到一搭建微服务项目编码实战(三)
学习时长: 22分37秒
39
从零到一搭建微服务项目编码实战(四)
学习时长: 30分3秒
40
从零到一搭建微服务项目编码实战(五)
学习时长: 44分29秒
41
从零到一搭建微服务项目编码实战(六)
学习时长: 22分7秒
42
从零到一搭建微服务项目编码实战(七)
学习时长: 15分1秒
43
从零到一搭建微服务项目编码实战(八)
学习时长: 1小时49分
44
从零到一搭建微服务项目编码实战(九)
学习时长: 29分1秒
45
从零到一搭建微服务项目编码实战(十)
学习时长: 48分10秒
46
从零到一搭建微服务项目编码实战(十一)
学习时长: 52分2秒
47
从零到一搭建微服务项目编码实战(十二)
学习时长: 46分3秒
48
从零到一搭建微服务项目编码实战(十三)
学习时长: 24分24秒
49
从零到一搭建微服务项目编码实战(十四)
学习时长: 31分41秒
50
从零到一搭建微服务项目编码实战(十五)
学习时长: 36分47秒
51
[补充章节]Spring Cloud Gateway聚合Swagger接口
学习时长: 22分12秒
52
[补充章节]微服务架构实战项目中整合Seata
学习时长: 24分3秒
53
[补充章节]微服务架构实战项目打包及部署
学习时长: 21分16秒
54
[补充章节]微服务架构实战项目中整合Sentinel
学习时长: 33分45秒
55
[补充章节]微服务架构实战项目中整合Seluth、Zipkin
学习时长: 2小时18分
56
[补充章节]链路追踪之ELK日志中心搭建
学习时长: 23分4秒
57
[补充章节]微服务架构实战项目中整合ELK日志中心
学习时长: 35分53秒
58
课程总结与展望
学习时长: 5分32秒
juejin_logo copyCreated with Sketch.

本章节的讲解代码下载地址如下:

tips
复制代码
链接: https://pan.baidu.com/s/1SyC6kv9LhlTG3IThP4aIQQ 提取码: 5ws6

承接前文,本章节会继续讲解微服务架构下订单微服务的编码改造。章节源码是在newbee-mall-cloud-dev-step15工程的基础上改造,工程命名为newbee-mall-cloud-dev-step16。

创建订单微服务模块

与其它微服务模块的创建过程一致,首先要创建订单微服务模块。在工程中新建一个newbee-mall-cloud-order-service模块,并在主pom.xml文件中增加该模块的配置,代码如下:

xml
复制代码
<modules> <!-- 新增订单微服务 --> <module>newbee-mall-cloud-order-service</module> <module>newbee-mall-cloud-shop-cart-service</module> <module>newbee-mall-cloud-recommend-service</module> <module>newbee-mall-cloud-goods-service</module> <module>newbee-mall-cloud-user-service</module> <module>newbee-mall-cloud-gateway-mall</module> <module>newbee-mall-cloud-gateway-admin</module> <module>newbee-mall-cloud-common</module> </modules>

该模块的目录结构设置与其它的功能模块类似,如下所示:

java
复制代码
newbee-mall-cloud-order-service // 订单微服务 ├── newbee-mall-cloud-order-api // 存放订单模块中暴露出去的用于远程调用的FeignClient类 └── newbee-mall-cloud-order-web // 订单API的代码及逻辑

新建订单微服务模块时,主要是参考了当时新建商品微服务时的步骤。笔者是直接将newbee-mall-cloud-dev-step05源码下newbee-mall-cloud-goods-service模块中的代码复制了过来,之后将模块名称和目录名称修改掉。

由于改造过程中是直接复制了newbee-mall-cloud-dev-step05源码下newbee-mall-cloud-goods-service模块中的代码,所以在修改完依赖配置后,就是修改包名,把ltd.goods.cloud.xxx的命名改为ltd.order.cloud.xxx,然后修改config包中的代码,包括全局异常处理配置类、Swagger配置类、自定义MVC配置类,主要是修改了这些类的类名。这样,就完成了一个订单微服务的初始构建工作。

订单微服务中的用户身份认证也需要进行处理,过程与之前微服务中的处理步骤类似。由于订单微服务中的接口涉及到商城端和后台管理系统,所以商城端用户和管理员用户两种身份相关的逻辑代码都要复制过来。接着,需要引入loadbalancer依赖和user-api依赖,并修改商城端用户和管理员用户token处理类中的逻辑代码,并通过OpenFeign来调用用户微服务中的接口,在订单微服务中实现两种用户的鉴权和信息获取了。

订单微服务编码

接下来,开始补充订单微服务中的业务代码,主要是把原来单体项目中的功能模块整合到订单微服务中。

订单微服务代码改造

打开订单微服务newbee-mall-cloud-order-web的工程目录,在ltd.order.cloud.newbee包下依次创建config包、dao包、entity包、service包,在resources目录下新增mapper文件夹用于存放Mapper文件。接着,直接将原单体API项目中订单模块相关的业务代码和Mapper文件依次复制进来即可,如下图所示。

image-20220907132740377

上述步骤完成后,最终的代码目录如下图所示。

WX20220907-133309@2x

最后,修改newbee-mall-cloud-order-web工程中的application.properties配置文件,主要是数据库连接参数及MyBatis扫描配置,代码如下所示:

properties
复制代码
# datasource config (MySQL) spring.datasource.name=newbee-mall-cloud-order-datasource spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/newbee_mall_cloud_order_db?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8&autoReconnect=true&useSSL=false spring.datasource.username=root spring.datasource.password=123456 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.maximum-pool-size=15 spring.datasource.hikari.auto-commit=true spring.datasource.hikari.idle-timeout=60000 spring.datasource.hikari.pool-name=hikariCP spring.datasource.hikari.max-lifetime=600000 spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.connection-test-query=SELECT 1 # mybatis config mybatis.mapper-locations=classpath:mapper/*Mapper.xml

本步骤中的源码,涉及到的数据库为newbee_mall_cloud_order_db,数据库表为tb_newbee_mall_order、tb_newbee_mall_order_item、tb_newbee_mall_user_address、tb_newbee_mall_order_address,开发过程中需要用到。除此之外,也会用到商品数据和用户数据,这部分数据就要使用远程调用技术了。

代码修改注意事项

在订单微服务的代码调整前,有些工具类已经被移动到公共模块newbee-mall-cloud-common中,所以在pom.xml中需要引入公共模块。同时,代码中使用到这些工具类的地方也需要处理一下引用路径。

除此之外,订单微服务中也有一些公共类,都放到了公共模块newbee-mall-cloud-common中。

Controller类中的接口地址都做了微调,与之前的URL不同。调整的原因主要是网关配置时方便一些。

网关模块配置

打开商城端网关newbee-mall-cloud-gateway-mall项目中的application.properties文件,新增关于订单微服务的路由信息,配置项为spring.cloud.gateway.routes.*,新增内容如下:

properties
复制代码
# 订单接口的路由配置 spring.cloud.gateway.routes[5].id=order-service-route spring.cloud.gateway.routes[5].uri=lb://newbee-mall-cloud-order-service spring.cloud.gateway.routes[5].order=1 spring.cloud.gateway.routes[5].predicates[0]=Path=/orders/mall/** # 收货地址接口的路由配置 spring.cloud.gateway.routes[6].id=order-service-route2 spring.cloud.gateway.routes[6].uri=lb://newbee-mall-cloud-order-service spring.cloud.gateway.routes[6].order=1 spring.cloud.gateway.routes[6].predicates[0]=Path=/mall/address/**

如果访问到网关项目的路径是以/orders/mall/和/mall/address/开头,就路由到订单微服务实例。

打开后台管理系统网关newbee-mall-cloud-gateway-admin项目中的application.properties文件,新增关于订单微服务的路由信息,配置项为spring.cloud.gateway.routes.*,新增内容如下:

properties
复制代码
# 订单接口的路由配置 spring.cloud.gateway.routes[5].id=order-service-route spring.cloud.gateway.routes[5].uri=lb://newbee-mall-cloud-order-service spring.cloud.gateway.routes[5].order=1 spring.cloud.gateway.routes[5].predicates[0]=Path=/orders/admin/**

如果访问到网关项目的路径是以/orders/admin开头,就路由到订单微服务实例。

订单微服务远程调用商品微服务和购物车微服务编码实践

按照上述步骤对订单微服务进行编码后,代码中依然会标红。被标红的代码及注释如下所示:

java
复制代码
@PostMapping("/saveOrder") @ApiOperation(value = "生成订单接口", notes = "传参为地址id和待结算的购物项id数组") public Result<String> saveOrder(@ApiParam(value = "订单参数") @RequestBody SaveOrderParam saveOrderParam, @TokenToMallUser MallUser loginMallUser) { int priceTotal = 0; if (saveOrderParam == null || saveOrderParam.getCartItemIds() == null || saveOrderParam.getAddressId() == null) { NewBeeMallException.fail(ServiceResultEnum.PARAM_ERROR.getResult()); } if (saveOrderParam.getCartItemIds().length < 1) { NewBeeMallException.fail(ServiceResultEnum.PARAM_ERROR.getResult()); } // 根据购物项id列表查询购物项列表并进行基本的逻辑验证 List<NewBeeMallShoppingCartItemVO> itemsForSave = newBeeMallShoppingCartService.getCartItemsForSettle(Arrays.asList(saveOrderParam.getCartItemIds()), loginMallUser.getUserId()); ... 省略部分代码 return ResultGenerator.genFailResult("生成订单失败"); }

在生成订单接口中,需要根据cartItemIds参数查询数据库中的一条或者多条购物项数据进行基本的逻辑验证,然后才能进行后续的业务逻辑。而订单微服务未连接购物项表所在的数据库,所以无法直接查询对应的购物项数据,这部分代码会标红。

java
复制代码
@Override @Transactional public String saveOrder(MallUser loginMallUser, MallUserAddress address, List<NewBeeMallShoppingCartItemVO> myShoppingCartItems) { List<Long> itemIdList = myShoppingCartItems.stream().map(NewBeeMallShoppingCartItemVO::getCartItemId).collect(Collectors.toList()); List<Long> goodsIds = myShoppingCartItems.stream().map(NewBeeMallShoppingCartItemVO::getGoodsId).collect(Collectors.toList()); // 查询商品数据 List<NewBeeMallGoods> newBeeMallGoods = newBeeMallGoodsMapper.selectByPrimaryKeys(goodsIds); // 检查是否包含已下架商品 List<NewBeeMallGoods> goodsListNotSelling = newBeeMallGoods.stream() .filter(newBeeMallGoodsTemp -> newBeeMallGoodsTemp.getGoodsSellStatus() != Constants.SELL_STATUS_UP) .collect(Collectors.toList()); if (!CollectionUtils.isEmpty(goodsListNotSelling)) { // goodsListNotSelling 对象非空则表示有下架商品 NewBeeMallException.fail(goodsListNotSelling.get(0).getGoodsName() + "已下架,无法生成订单"); } Map<Long, NewBeeMallGoods> newBeeMallGoodsMap = newBeeMallGoods.stream().collect(Collectors.toMap(NewBeeMallGoods::getGoodsId, Function.identity(), (entity1, entity2) -> entity1)); // 判断商品库存 for (NewBeeMallShoppingCartItemVO shoppingCartItemVO : myShoppingCartItems) { // 查出的商品中不存在购物车中的这条关联商品数据,直接返回错误提醒 if (!newBeeMallGoodsMap.containsKey(shoppingCartItemVO.getGoodsId())) { NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult()); } // 存在数量大于库存的情况,直接返回错误提醒 if (shoppingCartItemVO.getGoodsCount() > newBeeMallGoodsMap.get(shoppingCartItemVO.getGoodsId()).getStockNum()) { NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_COUNT_ERROR.getResult()); } } // 删除购物项 if (!CollectionUtils.isEmpty(itemIdList) && !CollectionUtils.isEmpty(goodsIds) && !CollectionUtils.isEmpty(newBeeMallGoods)) { if (newBeeMallShoppingCartItemMapper.deleteBatch(itemIdList) > 0) { List<StockNumDTO> stockNumDTOS = BeanUtil.copyList(myShoppingCartItems, StockNumDTO.class); // 修改商品库存 int updateStockNumResult = newBeeMallGoodsMapper.updateStockNum(stockNumDTOS); if (updateStockNumResult < 1) { NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_COUNT_ERROR.getResult()); } //生成订单号 String orderNo = NumberUtil.genOrderNo(); int priceTotal = 0; //保存订单 NewBeeMallOrder newBeeMallOrder = new NewBeeMallOrder(); newBeeMallOrder.setOrderNo(orderNo); newBeeMallOrder.setUserId(loginMallUser.getUserId()); //总价 for (NewBeeMallShoppingCartItemVO newBeeMallShoppingCartItemVO : myShoppingCartItems) { priceTotal += newBeeMallShoppingCartItemVO.getGoodsCount() * newBeeMallShoppingCartItemVO.getSellingPrice(); } if (priceTotal < 1) { NewBeeMallException.fail(ServiceResultEnum.ORDER_PRICE_ERROR.getResult()); } newBeeMallOrder.setTotalPrice(priceTotal); String extraInfo = ""; ... 省略部分代码 NewBeeMallException.fail(ServiceResultEnum.DB_ERROR.getResult()); } NewBeeMallException.fail(ServiceResultEnum.DB_ERROR.getResult()); } NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult()); return ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult(); }

同样的,在生成订单的业务层代码中,也有针对购物项表和商品表的操作,比如删除购物项数据、查询商品数据、修改商品库存,之后才能进行后续生成订单的业务逻辑。而订单微服务未连接购物项表和商品表所在的数据库,所以无法直接通过NewBeeMallShoppingCartItemMapper和GoodsMapper去完成对应的功能,这部分代码会标红。

因此,想要完成订单微服务的代码改造,必须要进行购物项数据查询、购物项数据删除、商品数据查询和商品库存修改部分代码的改造,由原本直接操作购物项表和商品表改为远程调用购物车微服务和商品微服务中的接口来完成这个逻辑。订单微服务不止要与用户微服务通信,还要与购物车微服务和商品微服务通信。这里的代码改造步骤如下所示。

第一步,在商品微服务增加修改库存的逻辑代码和对外暴露接口。

当前所需的查询购物项数据、删除购物项数据、查询商品数据和修改商品库存这四个远程调用操作,其中有3个都已经完成编码了,只有修改商品库存还未完成编码。

打开newbee-mall-cloud-goods-web工程,在NewBeeAdminGoodsInfoController类中新增接口如下:

java
复制代码
/** * 修改商品库存 */ @PutMapping("/updateStock") @ApiOperation(value = "修改库存", notes = "") public Result updateStock(@RequestBody UpdateStockNumDTO updateStockNumDTO) { return ResultGenerator.genSuccessResult(newBeeMallGoodsService.updateStockNum(updateStockNumDTO.getStockNumDTOS())); }

然后,打开newbee-mall-cloud-goods-api工程,在NewBeeCloudGoodsServiceFeign类中定义该接口使得其它微服务可以调用,新增代码如下:

java
复制代码
@PutMapping(value = "/admin/updateStock") Result<Boolean> updateStock(@RequestBody UpdateStockNumDTO updateStockNumDTO);

第二步,引入goods-api和shop-cart-api依赖。

打开newbee-mall-cloud-order-web工程下的pom.xml文件,增加与购物车微服务和商品微服务远程通信所需的newbee-mall-cloud-shop-cart-api模块和newbee-mall-cloud-goods-api模块,新增依赖配置如下:

xml
复制代码
<dependency> <groupId>ltd.goods.newbee.cloud</groupId> <artifactId>newbee-mall-cloud-goods-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>ltd.shopcart.newbee.cloud</groupId> <artifactId>newbee-mall-cloud-shop-cart-api</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>

第三步,增加关于购物车微服务和商品微服务中FeignClient的配置。

打开newbee-mall-cloud-goods-web工程,对启动类NewBeeMallCloudOrderServiceApplication上的@EnableFeignClients注解进行修改,增加对于NewBeeCloudShopCartServiceFeign和NewBeeCloudGoodsServiceFeign的声明,代码如下:

java
复制代码
@EnableFeignClients(basePackageClasses ={ltd.goods.cloud.newbee.openfeign.NewBeeCloudGoodsServiceFeign.class, ltd.shopcart.cloud.newbee.openfeign.NewBeeCloudShopCartServiceFeign.class, ltd.user.cloud.newbee.openfeign.NewBeeCloudUserServiceFeign.class})

接下来就可以直接使用NewBeeCloudShopCartServiceFeign和NewBeeCloudGoodsServiceFeign与购物车微服务、商品微服务进行远程通信了。

第四步,修改对于商品表和购物项表操作的代码。

打开newbee-mall-cloud-order-web工程,修改NewBeeMallOrderServiceImpl类中saveOrder()方法中的逻辑代码。删除原本直接操作购物项表和商品表的代码,然后依次注入NewBeeCloudShopCartServiceFeign类和NewBeeCloudGoodsServiceFeign类,并通过调用购物车微服务和商品微服务来完成查询购物项数据、删除购物项数据、查询商品数据和修改商品库存四个逻辑操作。这里,笔者把购物项数据的查询和前置判断也转移到业务方法中了。修改后的代码及相应的注释如下所示:

java
复制代码
@Autowired private NewBeeCloudGoodsServiceFeign goodsService; @Autowired private NewBeeCloudShopCartServiceFeign shopCartService; @Override @Transactional public String saveOrder(Long mallUserId, MallUserAddress address, List<Long> cartItemIds) { //调用购物车服务feign获取数据 Result<List<NewBeeMallShoppingCartItemDTO>> cartItemDTOListResult = shopCartService.listByCartItemIds(cartItemIds); if (cartItemDTOListResult == null || cartItemDTOListResult.getResultCode() != 200) { NewBeeMallException.fail("参数异常"); } List<NewBeeMallShoppingCartItemDTO> itemsForSave = cartItemDTOListResult.getData(); if (CollectionUtils.isEmpty(itemsForSave)) { //无数据 NewBeeMallException.fail("参数异常"); } List<Long> itemIdList = itemsForSave.stream().map(NewBeeMallShoppingCartItemDTO::getCartItemId).collect(Collectors.toList()); List<Long> goodsIds = itemsForSave.stream().map(NewBeeMallShoppingCartItemDTO::getGoodsId).collect(Collectors.toList()); //调用商品服务feign获取数据 Result<List<NewBeeMallGoodsDTO>> goodsDTOListResult = goodsService.listByGoodsIds(goodsIds); if (goodsDTOListResult == null || goodsDTOListResult.getResultCode() != 200) { NewBeeMallException.fail("参数异常"); } List<NewBeeMallGoodsDTO> newBeeMallGoods = goodsDTOListResult.getData(); //检查是否包含已下架商品 List<NewBeeMallGoodsDTO> goodsListNotSelling = newBeeMallGoods.stream() .filter(newBeeMallGoodsTemp -> newBeeMallGoodsTemp.getGoodsSellStatus() != 0) .collect(Collectors.toList()); if (!CollectionUtils.isEmpty(goodsListNotSelling)) { //goodsListNotSelling 对象非空则表示有下架商品 NewBeeMallException.fail(goodsListNotSelling.get(0).getGoodsName() + "已下架,无法生成订单"); } Map<Long, NewBeeMallGoodsDTO> newBeeMallGoodsMap = newBeeMallGoods.stream().collect(Collectors.toMap(NewBeeMallGoodsDTO::getGoodsId, Function.identity(), (entity1, entity2) -> entity1)); //判断商品库存 for (NewBeeMallShoppingCartItemDTO cartItemDTO : itemsForSave) { //查出的商品中不存在购物车中的这条关联商品数据,直接返回错误提醒 if (!newBeeMallGoodsMap.containsKey(cartItemDTO.getGoodsId())) { NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult()); } //存在数量大于库存的情况,直接返回错误提醒 if (cartItemDTO.getGoodsCount() > newBeeMallGoodsMap.get(cartItemDTO.getGoodsId()).getStockNum()) { NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_COUNT_ERROR.getResult()); } } //删除购物项 if (!CollectionUtils.isEmpty(itemIdList) && !CollectionUtils.isEmpty(goodsIds) && !CollectionUtils.isEmpty(newBeeMallGoods)) { //调用购物车服务feign删除数据 Result<Boolean> deleteByCartItemIdsResult = shopCartService.deleteByCartItemIds(itemIdList); if (deleteByCartItemIdsResult != null && deleteByCartItemIdsResult.getResultCode() == 200) { List<StockNumDTO> stockNumDTOS = BeanUtil.copyList(itemsForSave, StockNumDTO.class); UpdateStockNumDTO updateStockNumDTO = new UpdateStockNumDTO(); updateStockNumDTO.setStockNumDTOS(stockNumDTOS); //调用商品服务feign修改库存数据 Result<Boolean> updateStockResult = goodsService.updateStock(updateStockNumDTO); if (updateStockResult == null || updateStockResult.getResultCode() != 200) { NewBeeMallException.fail(ServiceResultEnum.PARAM_ERROR.getResult()); } if (!updateStockResult.getData()) { NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_COUNT_ERROR.getResult()); } ... 省略部分代码 NewBeeMallException.fail(ServiceResultEnum.DB_ERROR.getResult()); } NewBeeMallException.fail(ServiceResultEnum.DB_ERROR.getResult()); } NewBeeMallException.fail(ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult()); return ServiceResultEnum.SHOPPING_ITEM_ERROR.getResult(); }

功能测试

代码修改完成后,不要觉得就万事大吉了,测试步骤是不能漏掉的。一定要验证项目是否能正常启动,接口是否能正常调用,防止在代码移动过程中出现的一些小问题导致项目无法启动或者代码报错。在项目启动前需要启动Nacos Server和Redis Server,然后依次启动newbee-mall-cloud-order-web工程、newbee-mall-cloud-shop-cart-web工程、newbee-mall-cloud-user-web工程、newbee-mall-cloud-goods-web工程下的主类(如果想要测试网关功能还需要再启动两个网关模块下的主类)。启动成功后,就可以进行本章节的功能测试了。

首先打开用户微服务的Swagger界面,在浏览器中输入如下地址:

http://localhost:29000/swagger-ui/index.html

之后在该页面使用商城用户的登录接口获取一个token值用于后续的功能测试,比如笔者在测试时获取到了一个“c5b0a720e8068a186d9d3ff7ff3a28d8”的token值。

接下来打开订单微服务的Swagger界面,在浏览器中输入如下地址:

http://localhost:29040/swagger-ui/index.html

接着,就可以在Swagger提供的UI页面进行订单微服务中的接口测试了,页面显示内容如下。

image-20220912104120810

主要包括后台管理系统订单模块接口、个人地址模块接口和商城端订单操作相关接口。由于篇幅限制,这里只对商城端订单操作相关接口进行测试。

添加收货地址接口演示

下单时需要用户的收货地址信息,否则是无法正确的生成订单数据。点开“添加地址”,并点击Try it out按钮,并点击Try it out按钮,在参数栏填入收货地址的相关信息,在登录认证token的输入框中输入登录接口返回的Token字段值,如下图所示。

image-20220912112049398

点击Execute按钮,接口响应结果如下图所示。

image-20220912112118088

后端接口响应为“SUCCESS”则表示收货地址信息添加成功。此时,再去订单微服务的数据库中查看收货地址表中的数据,可以看到已经新增了一条地址信息了,该数据的主键id为2164,后续生成订单时会用到。

生成订单接口演示

点开“生成订单接口”,并点击Try it out按钮,并点击Try it out按钮,在参数栏填入当前用户的地址id和需要结算的购物项id列表,这里填入的数据都是刚刚演示时生成的数据(地址id为2164,购物项id为购物车微服务实战章节生成的数据,分别是7625和7626)。在登录认证token的输入框中输入登录接口返回的Token字段值,如下图所示。

image-20220912112712871

点击Execute按钮,接口响应结果如下图所示。

image-20220912112930008

如果结算时提交的数据都正确,就可以得到一个订单生成后的订单号字段,该字段的值在响应对象Result的data字段中,比如当前接口的测试结果,获取了值为“16629533442214515”的订单号,之后就能够使用该订单号来测试取消订单、模拟支付、订单详情都接口了。生成订单接口测试成功。

订单列表接口演示

点开“订单列表接口”,并点击Try it out按钮,并点击Try it out按钮,在参数栏填入页码和订单状态字段,在登录认证token的输入框中输入登录接口返回的Token字段值,就可以去查询当前用户的订单列表数据了,如下图所示。

image-20220912113113598

点击Execute按钮,接口响应结果如下图所示。

image-20220912113147251

请求成功。订单列表中所需的数据在Result类的data属性中,其中有分页信息、定案列表数据,每一条购物项中包括订单号、订单状态、下单时间、订单中包含的商品等内容。

这三个接口,对应到实际的项目页面中,是新蜂商城项目的添加收货地址、确认订单页面和订单列表页面,显示效果如下图所示。

address&settle&order-list

至此,下单流程中的部分功能就演示完成了,读者在测试时可以关注一下MySQL数据库中购物项表的变化。

功能测试完成且接口响应一切正常,表示订单微服务本身的功能编码完成,且远程调用用户微服务、商品微服务、购物车微服务也一切正常。在测试时,读者也可以通过debug模式启动项目,然后打上几个断点来查看接口测试时的完整过程。由于篇幅限制,笔者这里只演示了部分接口的测试过程,读者在测试时可以看看其它接口。除了在订单微服务项目的Swagger页面测试接口外,也可以通过商城端网关来访问这些接口进行功能测试。

总结

本章节中主要是订单模块在微服务架构下的编码改造,在订单微服务开发完成后,本课程实战项目已经完成了原单体商城项目中所有功能模块的开发与测试。当然,这不是终点,后续依然会补充一些必要的知识点进来。希望各位读者能够根据笔者提供的开发步骤顺利地完成本章节的项目修改。当然,读者如果有任何问题或者想要和笔者讨论的内容,都可以在评论区留下看法,笔者会根据读者的反馈和问题继续整理和完善本章节内容。

留言
评论 2
完结撒花
1
1
后续还会再补充一些内容,谢谢支持
点赞
回复